﻿'    This file is part of The Global Distribution System.

'    The Global Distribution System is free software: you can redistribute it and/or modify
'    it under the terms of the GNU General Public License as published by
'    the Free Software Foundation, either version 3 of the License, or
'    (at your option) any later version.

'    The Global Distribution System is distributed in the hope that it will be useful,
'    but WITHOUT ANY WARRANTY; without even the implied warranty of
'    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
'    GNU General Public License for more details.

'    You should have received a copy of the GNU General Public License
'    along with The Global Distribution System.  If not, see <http://www.gnu.org/licenses/>.

Public Class MainForm

#Region " Variables "

    Private IsClosing As Boolean = False
    Public WithEvents BC As New BackendClass()
    Private m_SortingColumn As ColumnHeader
    Private HashName As String = String.Empty

#End Region

#Region " Buttons "

    Private Sub btn_login_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_login.Click
        If tb_user.TextLength > 4 AndAlso tb_password.TextLength > 4 Then

            'Buttons
            EnableControl(btn_logoff, True)
            EnableControl(btn_login, False)

            'Textboxes
            EnableControl(tb_user, False)
            EnableControl(tb_password, False)
            EnableControl(tb_data, True)

            'Checkbox
            EnableControl(cb_remember, False)

            'RTB
            EnableControl(rtb_chat, True)

            'ListBox
            EnableControl(lb_users, True)

            'Generate Hash
            HashName = GenerateCode(tb_user.Text, tb_password.Text)

            'Send data.
            BC.SendMessage(New DLL.IndividualPerson With {.login = True, .person = String.Format("{0}!{1}", tb_user.Text, HashName)})

            tb_data.Focus()
            Me.AcceptButton = btn_send

            If My.Settings.Remember Then
                My.Settings.User = tb_user.Text
                My.Settings.Pass = tb_password.Text
            End If
            My.Settings.Save()
        End If

    End Sub

    Private Sub btn_logoff_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_logoff.Click

        'Buttons
        EnableControl(btn_logoff, False)
        EnableControl(btn_login, True)

        'Textboxes
        EnableControl(tb_user, True)
        EnableControl(tb_password, True)
        EnableControl(tb_data, False)

        'Checkbox
        EnableControl(cb_remember, True)

        'RTB
        EnableControl(rtb_chat, False)

        'ListBox
        EnableControl(lb_users, False)

        'Send data.
        BC.SendMessage(New DLL.IndividualPerson With {.login = False, .person = String.Format("{0}!{1}", tb_user.Text, HashName)})
        lb_users.Items.Clear()

    End Sub

    Private Sub tb_data_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tb_data.TextChanged
        btn_send.Enabled = tb_data.Text.Length > 0I
    End Sub

    Private Sub btn_send_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_send.Click
        BC.SendMessage(New DLL.ChatMessage With {.sender = String.Format("{0}!{1}", tb_user.Text, HashName), .message = tb_data.Text})
        tb_data.Clear()
    End Sub

    Private Sub tb_password_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tb_password.TextChanged
        tb_password.BackColor = If(tb_password.TextLength > 4, Drawing.Color.White, Drawing.Color.Red)
    End Sub

    Private Sub tb_user_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tb_user.TextChanged
        tb_user.BackColor = If(tb_user.TextLength > 4, Drawing.Color.White, Drawing.Color.Red)
    End Sub

    Private Sub cb_remember_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cb_remember.CheckedChanged
        My.Settings.Remember = cb_remember.Checked
        My.Settings.Save()
    End Sub

    Private Sub btn_browse_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_browse.Click
        Using OFD As New OpenFileDialog With {.Title = "Browse for a Pokémon", .Filter = "Pokémon File|*.pkm", .Multiselect = False, .InitialDirectory = Application.StartupPath}
            Select Case OFD.ShowDialog
                Case Windows.Forms.DialogResult.OK
                    tb_pkm_file.Text = OFD.FileName
            End Select
        End Using
    End Sub

    Private Sub btn_upload_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_upload.Click
        Dim PD As New DLL.PokemonData
        PD.PokemonName = IO.Path.GetFileNameWithoutExtension(tb_pkm_file.Text)
        PD.PokemonData = IO.File.ReadAllBytes(tb_pkm_file.Text)
        PD.ID = BC.MD5CalcFile(tb_pkm_file.Text)
        If PD.PokemonData.Length <= 236 Then
            btn_upload.Enabled = False
            btn_browse.Enabled = False
            BC.SendMessage(PD)
            If cb_auto_reserve.Checked Then BC.SendMessage(New DLL.ReservePokemon With {.ID = PD.ID, .Overwrite = True})
        End If
    End Sub

    Private Sub btn_search_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_search.Click
        BC.SendMessage(New DLL.SearchRequest With {.Search = True, .Name = tb_pkm_search.Text})
        LV_Search_pkm.Items.Clear()
        LV_Search_pkm.Items.Add(New ListViewItem With {.Text = "Please wait..."})
        LV_Search_pkm.Enabled = False
        btn_search.Enabled = False
        tb_pkm_search.Enabled = False
    End Sub

    Private Sub btn_clear_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_clear.Click
        LV_Search_pkm.Items.Clear()
    End Sub


    Private Delegate Sub dBtnEnable(ByVal btn As Button, ByVal enabled As Boolean)
    Private Sub BtnEnable(ByVal btn As Button, ByVal enabled As Boolean)
        If btn.InvokeRequired Then
            btn.Invoke(New dBtnEnable(AddressOf BtnEnable), btn, enabled)
        Else
            btn.Enabled = enabled
        End If
    End Sub

#End Region

#Region " Form and Control Events "

    Private Sub lb_users_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles lb_users.DoubleClick
        If lb_users.SelectedItem.ToString <> String.Empty Then
            Dim UserName() As String = lb_users.SelectedItem.ToString.Split("!"c)
            Dim ActualName As String = String.Empty
            System.Diagnostics.Debug.WriteLine(UserName.GetUpperBound(0))
            If UserName.GetUpperBound(0) > 1 Then
                For i As Integer = 0 To UserName.GetUpperBound(0) - 2
                    ActualName &= UserName(i) & "!"
                Next
            Else
                ActualName = UserName(0)
            End If
            tb_data.AppendText(String.Format("{0}: ", ActualName))
            tb_data.Focus()
        End If
    End Sub

    Private Sub TabControl1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TabControl1.SelectedIndexChanged
        Select Case TabControl1.SelectedIndex
            Case 0
                Me.AcceptButton = btn_search
                tb_pkm_search.Focus()
            Case 2
                Me.AcceptButton = btn_browse
                tb_pkm_file.Focus()
            Case 1
                Me.AcceptButton = Nothing
            Case 3
                Me.AcceptButton = If(btn_login.Enabled, btn_login, btn_send)
                If btn_login.Enabled Then tb_user.Focus() Else tb_data.Focus()
            Case Else
                Me.AcceptButton = Nothing
        End Select
    End Sub

    Private Sub TabPage2_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TabPage2.DragDrop
        If e.Data.GetDataPresent(DataFormats.FileDrop) Then
            Dim filePaths As String() = CType(e.Data.GetData(DataFormats.FileDrop), String())
            tb_pkm_file.Text = filePaths(0)
        End If
    End Sub

    Private Sub TabPage2_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TabPage2.DragEnter
        If e.Data.GetDataPresent(DataFormats.FileDrop) Then
            e.Effect = DragDropEffects.Copy
        Else
            e.Effect = DragDropEffects.None
        End If
    End Sub

    Private Sub tb_pkm_file_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tb_pkm_file.TextChanged
        btn_upload.Enabled = IO.File.Exists(tb_pkm_file.Text) AndAlso tb_pkm_file.Text.EndsWith(".pkm")
    End Sub

    Private Sub MainForm_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        IsClosing = True
        BC.Dispose()
        Application.Exit()
    End Sub

    Private Sub MainForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        BC = New BackendClass(My.Settings.RemoteIP)
        BC.Begin()
        cb_type.SelectedIndex = 0I
        If My.Settings.Remember Then
            tb_user.Text = My.Settings.User
            tb_password.Text = My.Settings.Pass
            cb_remember.Checked = True
        Else
            My.Settings.Remember = False
            My.Settings.User = String.Empty
            My.Settings.Pass = String.Empty
        End If
        tb_pkm_search.Focus()
    End Sub

    Private Sub LoadDataToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles LoadDataToolStripMenuItem.Click
        Dim RequestD As DLL.SearchRequest = New DLL.SearchRequest With {.Search = False}
        BC.SendMessage(RequestD)
        LV_Browse_pkm.Items.Add(New ListViewItem With {.Text = "Please wait..."})
        LV_Browse_pkm.Enabled = False
    End Sub

    Private Sub LV_Browse_pkm_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles LV_Browse_pkm.DoubleClick
        If LV_Browse_pkm.SelectedItems.Count > 0 Then
            BC.SendMessage(New DLL.RequestPokemonInformation With {.ID = LV_Browse_pkm.SelectedItems(0).Tag.ToString, .KeyOption = DLL.Options.Information})
        End If
    End Sub

    Private Sub LV_Search_pkm_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles LV_Search_pkm.DoubleClick
        If LV_Search_pkm.SelectedItems.Count > 0 Then
            BC.SendMessage(New DLL.RequestPokemonInformation With {.ID = LV_Search_pkm.SelectedItems(0).Tag.ToString, .KeyOption = DLL.Options.Information})
        End If
    End Sub

    Private Sub tb_pkm_search_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tb_pkm_search.TextChanged
        btn_search.Enabled = tb_pkm_search.TextLength >= 3
    End Sub

    Private Sub rtb_chat_LinkClicked(ByVal sender As Object, ByVal e As System.Windows.Forms.LinkClickedEventArgs) Handles rtb_chat.LinkClicked
        System.Diagnostics.Process.Start(e.LinkText.Trim())
    End Sub

#End Region

#Region " BC Events "

#Region " Delegates "

    Private Delegate Sub dDownload(ByVal info As DLL.PokemonData)
    Private Sub DownloadPokemonData(ByVal data As DLL.PokemonData)
        If Me.InvokeRequired Then
            Me.Invoke(New dDownload(AddressOf DownloadPokemonData), data)
        Else
            Dim SFD As New SaveFileDialog With {.Title = "Save Pokémon Data", .Filter = "Pokémon File|*.pkm", .InitialDirectory = Application.StartupPath}
            SFD.FileName = String.Format("{0}.pkm", data.PokemonName)
            Select Case SFD.ShowDialog
                Case Windows.Forms.DialogResult.OK
                    IO.File.WriteAllBytes(SFD.FileName, data.PokemonData)
            End Select
        End If
    End Sub

    Private Delegate Sub dShowInfoWindow(ByVal information As DLL.Information)
    Private Sub ShowInfoWindow(ByVal information As DLL.Information)
        If Me.InvokeRequired Then
            Me.Invoke(New dShowInfoWindow(AddressOf ShowInfoWindow), information)
        Else
            Dim PI As New PokemonInfo(information)
            PI.MainFormParent = Me
            PI.Show()
        End If
    End Sub

    Private Delegate Sub dEnableClient()
    Private Sub EnableStuff()
        If TabControl1.InvokeRequired Then
            TabControl1.Invoke(New dEnableClient(AddressOf EnableStuff))
        Else
            TabControl1.Enabled = True
        End If
    End Sub

    Private Delegate Sub dEnableControl(ByVal ctrl As Control, ByVal bool As Boolean)
    Private Sub EnableControl(ByVal ctrl As Control, ByVal bool As Boolean)
        If ctrl.InvokeRequired Then
            ctrl.Invoke(New dEnableControl(AddressOf EnableControl), ctrl, bool)
        Else
            ctrl.Enabled = bool
        End If
    End Sub

    Private Delegate Sub dFullListEdit(ByVal list As List(Of String))
    Private Sub FullListEdit(ByVal list As List(Of String))
        If lb_users.InvokeRequired Then
            lb_users.Invoke(New dFullListEdit(AddressOf FullListEdit), list)
        Else
            lb_users.Items.Clear()
            lb_users.Items.AddRange(list.ToArray)
            lb_users.Sorted = True
        End If
    End Sub

    Private Delegate Sub dInvididual(ByVal data As DLL.IndividualPerson)
    Private Sub Individual(ByVal data As DLL.IndividualPerson)
        If lb_users.InvokeRequired Then
            lb_users.Invoke(New dInvididual(AddressOf Individual), data)
        Else
            Select Case data.login
                Case True
                    If Not lb_users.Items.Contains(data.person) Then lb_users.Items.Add(data.person)
                Case False
                    SyncLock lb_users.Items
                        For i As Integer = lb_users.Items.Count - 1 To 0 Step -1
                            If lb_users.Items(i).ToString = data.person Then lb_users.Items.RemoveAt(i)
                        Next
                    End SyncLock
            End Select
        End If
    End Sub

    Private Delegate Sub dMessageHandle(ByVal data As DLL.ChatMessage)
    Private Sub MessageHandler(ByVal data As DLL.ChatMessage)
        If rtb_chat.InvokeRequired Then
            rtb_chat.Invoke(New dMessageHandle(AddressOf MessageHandler), data)
        Else

            Me.AppendStyledText(String.Format("{0}: ", data.sender), Drawing.FontStyle.Bold, rtb_chat, Drawing.Color.DarkBlue)
            Me.AppendStyledText(String.Format("{0}{1}", data.message, Environment.NewLine), Drawing.FontStyle.Regular, rtb_chat, Drawing.Color.Black)
            rtb_chat.ScrollToCaret()

        End If
    End Sub

    ''' <summary>
    ''' Appends styled text to the specified RichTextBox.
    ''' </summary>
    ''' <param name="text">The text to add.</param>
    ''' <param name="Style">The font style to add.</param>
    ''' <param name="RTB">The RTB to edit.</param>
    ''' <remarks></remarks>
    Private Sub AppendStyledText(ByVal text As String, ByVal Style As Drawing.FontStyle, ByVal RTB As RichTextBox, ByVal color As Drawing.Color)

        'First Append the new text.
        RTB.AppendText(text)

        'Now find the start selection.
        RTB.SelectionStart = RTB.Text.Length - text.Length

        'Now select the appropriate length.
        RTB.SelectionLength = text.Length

        'Apply the style
        RTB.SelectionFont = New System.Drawing.Font(RTB.Font, Style)
        RTB.SelectionColor = color

    End Sub

#End Region

    Private Sub BC_ChatFullList(ByVal sender As Object, ByVal e As DLL.FullList) Handles BC.ChatFullList
        Call FullListEdit(e.userlist)
    End Sub

    Private Sub BC_ChatIndividual(ByVal sender As Object, ByVal e As DLL.IndividualPerson) Handles BC.ChatIndividual
        If e.login = True AndAlso e.person <> HashName Then Call Individual(e)
    End Sub

    Private Sub BC_ChatMessage(ByVal sender As Object, ByVal e As DLL.ChatMessage) Handles BC.ChatMessage
        Call MessageHandler(e)
    End Sub

    Private Sub BC_ConnectionEstablished(ByVal sender As Object) Handles BC.ConnectionEstablished
        EnableStuff()
        BC.SendMessage(New DLL.MessageStructure With {.Message = "0"})
    End Sub

    Private Sub BC_ConnectionFailed(ByVal sender As Object, ByVal ex As System.Exception) Handles BC.ConnectionFailed
        If Not IsClosing Then
            Select Case MessageBox.Show("I'm sorry, but there was a connection error! You can press OK to see the error data or Cancel to close.", "Error!", MessageBoxButtons.OKCancel, MessageBoxIcon.Error)
                Case Windows.Forms.DialogResult.OK
                    MessageBox.Show(String.Format("{0}{1}Copy this box by pressing Ctrl + C and post it for Shiny Jirachi to see.", ex.ToString, Environment.NewLine), "Stack Trace", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Select
            Application.Exit()
        End If
    End Sub

    Private Sub BC_DownloadingData(ByVal sender As Object, ByVal data As DLL.PokemonData) Handles BC.DownloadingData
        Call DownloadPokemonData(data)
    End Sub

    Private Sub BC_IncomingInformation(ByVal sender As Object, ByVal data As DLL.Information) Handles BC.IncomingInformation
        Call ShowInfoWindow(data)
    End Sub

    Private Sub BC_MessageFromServer(ByVal sender As Object, ByVal message As String) Handles BC.MessageFromServer
        Select Case message
            Case "0" 'Reservation Accepted
                MessageBox.Show("Your reservation has been accepted. Please connect to the Global Trade Station to receive your Pokémon.", "Reservation Completed.", MessageBoxButtons.OK, MessageBoxIcon.Information)
            Case "1" 'Reservation Rejected
                MessageBox.Show("Your reservation was rejected because you already have one on the server. Please enable the 'Override Reservations' option in the Settings Tab of the program", "Reservation Rejected", MessageBoxButtons.OK, MessageBoxIcon.Error)
            Case "2" 'Upload is Successful
                MessageBox.Show("Your upload was processed and completed successfully! Thank you for submitting your Pokémon to the Global Distribution System.", "Upload Successful!", MessageBoxButtons.OK, MessageBoxIcon.Information)
                BtnEnable(btn_upload, True)
                BtnEnable(btn_browse, True)
            Case "3" 'Upload has failed
                MessageBox.Show("Your upload was rejected. Possible reasons are that the Pokémon is already on the Global Distribution System, the server request timed out, or there was an error saving your Pokémon", "Upload rejected", MessageBoxButtons.OK, MessageBoxIcon.Error)
                BtnEnable(btn_upload, True)
                BtnEnable(btn_browse, True)
        End Select
    End Sub

    Private Sub BC_SearchResults(ByVal sender As Object, ByVal e As BackendClass.SearchResultObject) Handles BC.SearchResults
        Select Case e.IsSearch
            Case True
                'First Tab
                LV_Search_pkm.Invoke(New d_LV_Search_Add(AddressOf LV_Search_Add), e.Result)
            Case False
                '2nd tab
                LV_Browse_pkm.Invoke(New d_LV_Browse_Add(AddressOf LV_Browse_Add), e.Result)
        End Select
    End Sub

#End Region

#Region " ListView crap "

    Private Sub ColumnClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ColumnClickEventArgs) Handles LV_Browse_pkm.ColumnClick, LV_Search_pkm.ColumnClick
        ' Get the new sorting column.
        Dim LV As ListView = CType(sender, ListView)
        Dim new_sorting_column As ColumnHeader = LV.Columns(e.Column)
        ' Figure out the new sorting order.
        Dim sort_order As System.Windows.Forms.SortOrder
        If m_SortingColumn Is Nothing Then
            ' New column. Sort ascending.
            sort_order = SortOrder.Ascending
        Else ' See if this is the same column.
            If new_sorting_column.Equals(m_SortingColumn) Then
                ' Same column. Switch the sort order.
                If m_SortingColumn.Text.StartsWith("> ") Then
                    sort_order = SortOrder.Descending
                Else
                    sort_order = SortOrder.Ascending
                End If
            Else
                ' New column. Sort ascending.
                sort_order = SortOrder.Ascending
            End If
            ' Remove the old sort indicator.
            m_SortingColumn.Text = m_SortingColumn.Text.Substring(2)
        End If
        ' Display the new sort order.
        m_SortingColumn = new_sorting_column
        If sort_order = SortOrder.Ascending Then
            m_SortingColumn.Text = "> " & m_SortingColumn.Text
        Else
            m_SortingColumn.Text = "< " & m_SortingColumn.Text
        End If
        ' Create a comparer.
        LV.ListViewItemSorter = New clsListviewSorter(e.Column, sort_order)
        ' Sort.
        LV.Sort()
    End Sub

    Private Delegate Sub d_LV_Search_Add(ByVal data As List(Of String))
    Private Sub LV_Search_Add(ByVal data As List(Of String))
        Try
            LV_Search_pkm.Items.Clear()
            LV_Search_pkm.BeginUpdate()

            For Each item As String In data
                Dim StringData() As String = item.Split("|"c)
                Dim LVI As New ListViewItem With {.Text = StringData(0), .Tag = StringData(1)}
                LVI.SubItems.Add(New ListViewItem.ListViewSubItem With {.Text = If(StringData(2) = "127.0.0.1", "No", "Yes")})
                LVI.SubItems.Add(New ListViewItem.ListViewSubItem With {.Text = StringData(3)})
                LV_Search_pkm.Items.Add(LVI)
            Next

            LV_Search_pkm.EndUpdate()
            LV_Search_pkm.Sort()
            LV_Search_pkm.Enabled = True
            btn_search.Enabled = True
            tb_pkm_search.Enabled = True
        Catch ex As Exception
            MessageBox.Show(ex.ToString)
        End Try

    End Sub


    Private Delegate Sub d_LV_Browse_Add(ByVal data As List(Of String))
    Private Sub LV_Browse_Add(ByVal data As List(Of String))
        Try
            LV_Browse_pkm.Items.Clear()
            LV_Browse_pkm.BeginUpdate()

            For Each item As String In data
                Dim StringData() As String = item.Split("|"c)
                Dim LVI As New ListViewItem With {.Text = StringData(0), .Tag = StringData(1)}
                LVI.SubItems.Add(New ListViewItem.ListViewSubItem With {.Text = If(StringData(2) = "127.0.0.1", "No", "Yes")})
                LVI.SubItems.Add(New ListViewItem.ListViewSubItem With {.Text = StringData(3)})
                LV_Browse_pkm.Items.Add(LVI)
            Next

            LV_Browse_pkm.EndUpdate()
            LV_Browse_pkm.Enabled = True
        Catch ex As Exception
            MessageBox.Show(ex.ToString)
        End Try

    End Sub

#End Region

#Region " Functions "

    ''' <summary>
    ''' Generate Secure Code.
    ''' </summary>
    ''' <param name="user">the username</param>
    ''' <param name="pass">The plain-text password</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function GenerateCode(ByVal user As String, ByVal pass As String) As String
        'Generate the pass hash.
        Dim hash As String = getMD5Hash(pass)
        hash = hash.Remove(5, hash.Length - 6)

        'generate the user hash.
        Dim uhash As String = getMD5Hash(user)
        uhash = uhash.Remove(0, uhash.Length - 4)

        'now hash the combined string.
        Dim combined_hash As String = getMD5Hash(String.Format("{0}{1}", hash, uhash))

        'Truncate everything but the first 6 characters.
        combined_hash = combined_hash.Remove(6, combined_hash.Length - 7)

        Return combined_hash
    End Function

    ''' <summary>
    ''' Get the MD5 Hash of a String
    ''' </summary>
    ''' <param name="strToHash">The String to Hash</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function getMD5Hash(ByVal strToHash As String) As String
        Dim md5Obj As New Security.Cryptography.MD5CryptoServiceProvider
        Dim bytesToHash() As Byte = System.Text.Encoding.ASCII.GetBytes(strToHash)

        bytesToHash = md5Obj.ComputeHash(bytesToHash)

        Dim strResult As String = ""

        For Each b As Byte In bytesToHash
            strResult += b.ToString("x2")
        Next

        Return strResult
    End Function

#End Region

End Class